import { Kwidget } from "../kWidget.js";
import tinycolor from "./tinycolor.js";
import "./style.css";
export const colorTree = {
  tag: "section",
  className: "color-picker",
  children: [
    {
      tag: "div",
      className: "picker-head",
      children: [
        {
          tag: "div",
          className: "brightness-icon",
        },
        {
          tag: "div",
          className: "color-string",
          value: "#ff0000",
        },
        {
          tag: "div",
          className: "picker-head-close",
          value: "×",
        },
      ],
    },
    {
      tag: "div",
      className: "picker-body",
      children: [
        {
          tag: "div",
          className: "saturation-box",
          children: [
            {
              tag: "div",
              className: "saturation-picker",
            },
            {
              tag: "canvas",
              className: "saturation-canvas",
            },
          ],
        },
        {
          tag: "div",
          className: "strips",
          children: [
            {
              tag: "div",
              className: "strip alpha",
              children: [
                {
                  tag: "div",
                  className: "slider",
                },
              ],
            },
            {
              tag: "div",
              className: "strip hue",
              children: [
                {
                  tag: "div",
                  className: "slider",
                },
              ],
            },
          ],
        },
      ],
    },
    {
      tag: "div",
      className: "picker-footer",
      children: [
        {
          tag: "span",
          className: "picker-footer-label",
          value: "最近使用",
        },
        {
          tag: "div",
          className: "picker-footer-body",
          children: [
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#BC0010"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#FA0019"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#FCC028"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#FDFF31"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#94D156"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#20B153"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#2DB0EE"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#1D70BE"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#07205F"
            },
            {
              tag: "span",
              className: "picker-footer-block",
              bgColor: "#702E9E"
            },
            
          ],
        },
      ],
    },
  ],
};

class KColorPicker extends Kwidget {
  root = document.documentElement;
  constructor(el, options) {
    super();
    this.colorDom = null;
    this.color = "#ff0000";
    this.currentColor = null;
    this.onColorChange = null;
    this.colorTypes = ["hex", "rgb", "hsl", "hsv"];
    this.initColorPicker({ width: 200 });
  }
  initColorPicker(setting = { el: document.body, width: 240 }) {
    this.colorDom = this.createColorElements(colorTree);
    setting.el
      ? setting.el.appendChild(this.colorDom)
      : document.body.appendChild(this.colorDom);
    this.root.style.setProperty(
      "--picker-width",
      setting.width ? setting.width + "px" : "240px"
    );
    this.start();
    this.showColorPicker(true);
    this.eventBindingHandle();
    return this.colorDom;
  }
  createColorElements(domTree) {
    let el = null;
    for (const key in domTree) {
      if (key === "tag") {
        el = document.createElement(domTree[key]);
      } else if (key === "className" && el instanceof HTMLElement) {
        el.setAttribute("class", domTree[key]);
      } else if (key === "value" && el instanceof HTMLElement) {
        el.innerText = domTree[key];
      } else if (key === "bgColor" && el instanceof HTMLElement) {
        el.setAttribute("style", `background-color: ${domTree[key]}`);
      } else if (domTree.hasOwnProperty(key) && key === "children") {
        domTree[key].forEach((child) => {
          let el2 = this.createColorElements(child);
          el.appendChild(el2);
        });
      }
    }
    return el;
  }

  start() {
    this.canvas = document.querySelector(".saturation-canvas"); // 画布
    this.colorBox = document.querySelector(".saturation-box"); // 画布盒子
    this.picker = this.colorBox.querySelector(".saturation-picker"); // 选择器指针
    this.alphaStrip = document.querySelector(".strip.alpha"); // 透明带
    this.alphaSlider = this.alphaStrip.querySelector(".slider"); // 透明滑块
    this.hueStrip = document.querySelector(".strip.hue"); // 色调带
    this.hueSlider = this.hueStrip.querySelector(".slider"); // 色调滑块

    this.head = document.querySelector(".picker-head"); // 头部
    this.colorString = document.querySelector(".color-string"); // 头部颜色值
    this.brightnessIcon = document.querySelector(".brightness-icon"); // 亮度icon

    this.closeDOM = document.querySelector(".picker-head-close");

    // 饱和度处理函数
    this.pickingSaturationHandler = null;
    // 色调处理函数
    this.pickingHueHandler = null;
    // 透明度处理函数
    this.pickingAlphaHandler = null;

    this.saturation = 1; // 饱和度 0-1
    this.brightness = 1; // 亮度 0-1
    this.alpha = 1; // 透明度 0-1
    this.hue = 0; // 色调 0-360deg
    this.currentColorType = "hex"; // 当前颜色类型

    this.drawSaturationPicker();
  }
  // 绘制调色面板
  drawSaturationPicker() {
    const ctx = this.canvas.getContext("2d");
    ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    ctx.fillStyle = tinycolor(`hsv ${this.hue} 1 1`).toHexString();
    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

    const whiteGradient = ctx.createLinearGradient(0, 0, this.canvas.width, 0);
    whiteGradient.addColorStop(0, "#fff");
    whiteGradient.addColorStop(1, "transparent");
    ctx.fillStyle = whiteGradient;
    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

    const blackGradient = ctx.createLinearGradient(0, 0, 0, this.canvas.height);
    blackGradient.addColorStop(0, "transparent");
    blackGradient.addColorStop(1, "#000");
    ctx.fillStyle = blackGradient;
    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
  }
  // 设置颜色字符串
  setColorString() {
    let str = "";
    const opaque = this.currentColor.getAlpha() === 1;
    switch (this.currentColorType) {
      case "hex":
        str = opaque
          ? this.currentColor.toHexString()
          : this.currentColor.toHex8String();
        break;
      case "rgb":
        str = this.currentColor.toRgbString();
        break;
      case "hsl":
        str = this.currentColor.toHslString();
        break;
      case "hsv":
        str = this.currentColor.toHsvString();
        break;
      default:
        break;
    }
    if (str) {
      this.colorString.textContent = str;
    }
  }
  // 设置当前颜色
  setCurrentColor(colorString) {
    if (colorString) {
      this.currentColor = tinycolor(colorString);
    } else {
      this.currentColor = tinycolor(
        `hsva(${this.hue},${this.saturation * 100}%, ${
          this.brightness * 100
        }%, ${this.alpha})`
      );
    }
    this.color = this.currentColor.toHex8String();
    if (this.onColorChange) {
      this.onColorChange(this.currentColor.toHex8String());
    }
    this.head.style.backgroundColor = this.currentColor.toHex8String();
    this.setColorString();
    const isBgDark = this.brightness < 0.5 || this.alpha < 0.5;
    this.colorString.style.color = isBgDark ? "#fff" : "#000";
    this.brightnessIcon.style.filter = isBgDark ? "invert(1)" : "invert(0)";
    document.documentElement.style.setProperty("--color", this.color);
  }
  // 色调面板mousemove
  handleMouseMove(target, callback, onHanlerCreate) {
    const rect = target.getBoundingClientRect();
    const { left, top, width, height } = rect;

    const handler = (e) => {
      const { clientX, clientY } = e;
      let x = clientX - left;
      let y = clientY - top;
      let xRatio, yRatio;
      if (x <= 0) {
        xRatio = 0;
        x = 0;
      } else if (x > width) {
        xRatio = 1;
        x = width;
      } else {
        xRatio = x / width;
      }

      if (y <= 0) {
        yRatio = 0;
        y = 0;
      } else if (y > height) {
        yRatio = 1;
        y = height;
      } else {
        yRatio = y / height;
      }
      callback({
        x,
        y,
        xRatio,
        yRatio,
      });
    };

    onHanlerCreate(handler);
    window.addEventListener("mousemove", handler);
  }
  // color picker组件显示和隐藏
  showColorPicker(isShow, pos = { x: 300, y: 300 }) {
    if (isShow) {
      this.colorDom.setAttribute("style", "display: flex");
      this.colorDom.style.left = pos.x + "px";
      this.colorDom.style.top = pos.y + "px";
    } else {
      this.colorDom.setAttribute("style", "display: none");
    }
  }
  // mousedown设置颜色
  setColorForMousedown(target, event) {
    const rect = target.getBoundingClientRect();
    const { left, top, width, height } = rect;
    let x, y, xRatio, yRatio;
    x = event.clientX - left;
    xRatio = x / width;
    y = event.clientY - top;
    yRatio = y / height;
    return { x, y, xRatio, yRatio };
  }
  // 根据color 求出hueStrip位置
  setPosForColor(bgStr) {
    this.currentColor = tinycolor(bgStr);
    const rect = this.hueStrip.getBoundingClientRect();
    const { width, height } = rect;
    let hsvaStr = this.currentColor.toHsvString();
    let hsvaArr = hsvaStr
      .substring(hsvaStr.indexOf("(") + 1, hsvaStr.indexOf(")"))
      .split(",")
      .map((it) => parseInt(it));
    [this.hue, this.saturation, this.brightness] = hsvaArr;
    this.saturation /= 100;
    this.brightness /= 100;
    let hueX = (this.hue / 360) * width;
    let pickerX = this.saturation * width;
    let pickerY = (1 - this.brightness) * height;
    this.hueSlider.style.left = hueX + "px";
    this.picker.style.left = pickerX + "px";
    this.picker.style.top = pickerY + "px";
    this.setCurrentColor();
    this.drawSaturationPicker();
    return { hueX, pickerX, pickerY };
  }
  // 事件注册中心
  eventBindingHandle() {
    // 关闭color picker 的icon事件
    this.closeDOM.addEventListener("click", (e) => {
      this.showColorPicker(false);
    });
    // color
    this.colorString.addEventListener("click", (e) => {
      let index = this.colorTypes.indexOf(this.currentColorType);
      if (index < this.colorTypes.length - 1) {
        index++;
      } else {
        index = 0;
      }
      this.currentColorType = this.colorTypes[index];
      this.setColorString();
    });
    this.colorBox.addEventListener("mousedown", (e) => {
      let { x, y, xRatio, yRatio } = this.setColorForMousedown(
        this.colorBox,
        e
      );
      this.picker.style.left = x + "px";
      this.picker.style.top = y + "px";
      this.saturation = xRatio;
      this.brightness = 1 - yRatio;
      this.setCurrentColor();

      this.handleMouseMove(
        this.colorBox,
        ({ x, y, xRatio, yRatio }) => {
          this.picker.style.left = x + "px";
          this.picker.style.top = y + "px";
          this.saturation = xRatio;
          this.brightness = 1 - yRatio;
          this.setCurrentColor();
        },
        (handler) => {
          this.pickingSaturationHandler = handler;
        }
      );
    });

    window.addEventListener("mouseup", (e) => {
      window.removeEventListener("mousemove", this.pickingSaturationHandler);
    });

    this.alphaStrip.addEventListener("mousedown", (e) => {
      let { x, y, xRatio, yRatio } = this.setColorForMousedown(
        this.alphaStrip,
        e
      );
      this.alphaSlider.style.left = x + "px";
      this.alpha = 1 - xRatio;
      this.setCurrentColor();

      this.handleMouseMove(
        this.alphaStrip,
        ({ x, xRatio }) => {
          this.alphaSlider.style.left = x + "px";
          this.alpha = 1 - xRatio;
          this.setCurrentColor();
        },
        (handler) => {
          this.pickingAlphaHandler = handler;
        }
      );
    });

    window.addEventListener("mouseup", (e) => {
      window.removeEventListener("mousemove", this.pickingAlphaHandler);
    });
    this.hueStrip.addEventListener("mousedown", (e) => {
      let { x, y, xRatio, yRatio } = this.setColorForMousedown(
        this.hueStrip,
        e
      );
      this.hueSlider.style.left = x + "px";
      this.hue = xRatio * 360;
      this.setCurrentColor();
      this.drawSaturationPicker();

      this.handleMouseMove(
        this.hueStrip,
        ({ x, xRatio }) => {
          this.hueSlider.style.left = x + "px";
          this.hue = xRatio * 360;
          console.log(this.hue);
          this.setCurrentColor();
          this.drawSaturationPicker();
        },
        (handler) => {
          this.pickingHueHandler = handler;
        }
      );
    });

    window.addEventListener("mouseup", (e) => {
      window.removeEventListener("mousemove", this.pickingHueHandler);
    });

    let commonlyColor = document.querySelectorAll(".picker-footer-body")[0];
    commonlyColor.addEventListener("mousedown", (evt) => {
      let targetStyle = getComputedStyle(evt.target);
      let bgStr = targetStyle.getPropertyValue("background-color");
      this.setPosForColor(bgStr);
    });
  }
}

Kwidget.defineCustomElement("k-color-picker", KColorPicker)
export { KColorPicker } 
